
`include "branchPredictor.v"
`include "tlb.v"
`include "fakeCache.v"

///`include "sumador4.v"

module Fetch(clock,reset,stop,WbFe_itlbwr,WbFe_itlbwridx,WbFe_itlbwren,DeFe_pcexception, DeFe_jumpsys,AlFe_pcoriginal,AlFe_pctarget, AlFe_error, AlFe_salta,SysFe_cacheline,SysFe_cachewren, SysFe_buswe,FeDe_pcactual,FeDe_pcmes, FeDe_pcprediction,FeDe_taken,FeDe_instruction,FeDe_nop,FeDe_excp,FeSys_address,FeSys_request,FeSys_busAck,FeSys_operation,FeFe_pcout,FeFe_pcin,WbFe_exception);
	input clock, reset, stop;
	
	//Control de la TLB
	
	// DeFe_itlbwr
	// [2:0]: Protection
	// [7:3]: Physical Page Number
	// [13:8]: Virtual Tag
	input [13:0] WbFe_itlbwr;
	input [2:0]  WbFe_itlbwridx;
	input        WbFe_itlbwren;
	
	// Consulta del TLB; Consulta Cache de instruccións, entrada
	// Sumador+4 
	input [15:0] FeFe_pcin;
	
	//Control de Salts
	input [15:0] AlFe_pctarget;
	input [15:0] AlFe_pcoriginal;
	input AlFe_error;
	input AlFe_salta;
	
	//Escriure a la cache d'instruccions una linia de Mem.
	input [63:0]  SysFe_cacheline;
	input        SysFe_cachewren;
	input SysFe_buswe;
	
	//Enviar PC i Instrucció a Decode
	output [15:0] FeDe_pcactual, FeDe_pcmes, FeDe_pcprediction;
	output [15:0] FeDe_instruction;
	output FeDe_nop;
	output  FeDe_taken;
	reg [15:0] FeDe_instruction;
	reg FeDe_nop;
	
	//Execpcions que s'envien a Decode
	//Bit 0: ITLB cache miss
	output [15:0]  FeDe_excp;
	reg[15:0]FeDe_excp;
	
	input [15:0] DeFe_pcexception; 
	input DeFe_jumpsys;
	input WbFe_exception;
	
	//Demanar una linea de cache a la Mem.
	output [15:0] FeSys_address;
	output FeSys_busAck;
	output [2:0] FeSys_operation;
	output FeSys_request;
	
	output [15:0] FeFe_pcout;
	
	reg [15:0] FeFe_pcout;
	reg FeSys_busack;
	reg [15:0] FeSys_address;
	reg [2:0] FeSys_operation;
	reg FeSys_request;
	
	
	reg ignoreCacheLine;
	reg enviarnops;	
	
	always @ (reset==1)
		begin
		
		end
	
	
	//Calcul de FeDe_pcmes
	//	FeFe_pcin=FeFe_pcin+2;
	
	//Calcul de FeDe_pcactual
	//FeDe_pcactual=FeFe_pcin;
	
	//Calcul de FeDe_pcprediction
	wire wBpHit;
	branchPredictor BP(clock,FeFe_pcout,AlFe_pcoriginal,AlFe_pctarget,AlFe_salta,AlFe_error,wBpHit,FeDe_taken,FeDe_pcprediction,reset);
	
	//Output signals of TLB -> to the Instructions CACHE
	wire tlb_Hit;
	wire[4:0] tlb_fisicaOut;
	wire[2:0] tlb_protOut;
	
	tlb TLB(FeFe_pcin[15:10],WbFe_itlbwr[7:3],WbFe_itlbwr[13:8],WbFe_itlbwr[2:0],WbFe_itlbwridx,WbFe_itlbwren,reset,clock,tlb_Hit,tlb_fisicaOut,tlb_protOut);
	
	
	wire wCacheHit;
	wire [15:0] wCacheOut;
	//cache Cache(tlb_fisicaOut,SysFe_cacheline,wCacheWEn,clock,reset,stop,wCacheHit,wCacheOut);
	cacheins Cache(clock,FeFe_pcin[9:3],SysFe_cacheline,FeFe_pcin[2:0],wCacheWEn,reset,tlb_fisicaOut,wCacheOut,wCacheHit);
	
	//Gestio Cache
	reg wCacheWEn = 0;
	
	
	always @ (negedge clock)
		begin
			if(reset==1)
				begin
					FeFe_pcout = 0;
					enviarnops = 0;
					ignoreCacheLine = 0;
					wCacheWEn = 0;
					//FeDe_nop = 1;
					FeSys_request = 0;
				end
				
			//si hi hi ha miss a la cache d'instruccions
			if(wCacheHit == 0 /*&& reset==0*/)
				begin
					enviarnops = 1;
					FeSys_request = 1;
					FeDe_instruction = 16'b0000000000000000;
				end
			
			// control del multiplexor, per al seguent PC
			if(stop == 0)
				begin
					if(enviarnops==1)
						begin
							if(WbFe_exception==1 || DeFe_jumpsys==1)
								begin                                         
									FeFe_pcout=DeFe_pcexception;            
								end
							else 
								if(AlFe_error==1)
									begin
										FeFe_pcout=AlFe_pctarget;
									end
								else
									FeFe_pcout=FeFe_pcin;
						end
					else
						if(WbFe_exception==1 || DeFe_jumpsys==1)
							begin                                         
								FeFe_pcout=DeFe_pcexception;            
							end                                           
						else                                          
							if(AlFe_error==1)                       
								begin                                 
									FeFe_pcout=AlFe_pctarget;
								end
							else                                  
								if(wBpHit==1)              
									begin                         
										FeFe_pcout=FeDe_pcprediction;                          
									end
								else
									FeFe_pcout=FeFe_pcin + 2;               
				end
			
		if(tlb_Hit==1)
			begin
				FeDe_excp = 0;
			end
		else
			begin
				FeDe_excp = 0;
				FeDe_excp[4] = 1;
			end
			
			
			// seleccionem la instrucció a enviar
			if(stop == 0)
				begin
					if(enviarnops == 0)
						begin
							FeDe_instruction = wCacheOut;
							FeDe_nop = 0;
						end
					else
						FeDe_nop = 1;
				end
			
			
			//si ens arriba un error de predicció des de la ALU
			if(stop == 0)
				begin
					
					if(enviarnops)
						begin
							if(AlFe_error==1)
								begin
									ignoreCacheLine = 1;		
								end
							
						end
					
				end
			
			
		end         
	
	
	
	
	
	always @ (SysFe_buswe==1)
		begin		 
			FeSys_request = 0;
			FeSys_operation=001;
			FeSys_address={tlb_fisicaOut,FeFe_pcin[9:0]};
		end
	
	
	always @ (SysFe_cachewren==1 )
		begin
			if(ignoreCacheLine == 0)
				begin
					wCacheWEn = 1;
				end
			else
				begin	
					ignoreCacheLine = 0;
					enviarnops = 0;
				end
			
		end	
	
	
	
	
	
	
	always @ (wCacheWEn == 1)
		begin
			if(wCacheHit==1)
				begin
					wCacheWEn = 0;
					enviarnops = 0;
				end
		end			  
	
endmodule

